<template>
	<el-select :value="inputText" v-bind="selectConfig" :disabled="disabled" @clear="handleSelectClear" @remove-tag="handleRemoveTag">
		<el-tree slot="empty" :data="list" v-bind="treeConfig" @node-click="handleNodeClick" @check="handleCheckChange"></el-tree>
	</el-select>
</template>

<script>
import emitter from 'element-ui/src/mixins/emitter';
export default {
	name: 'swTreeSelect',
	mixins: [emitter],
	props: {
		value: [Array, String],
		list: { type: Array, default: () => [] },
		nodeKey: { type: String, default: 'id' },
		placeholder: { type: String, default: '' },
		multiple: { type: Boolean, default: false },
		disabled: { type: Boolean, default: false },
		clearable: { type: Boolean, default: false },
		filterable: { type: Boolean, default: false },
		collapseTags: { type: Boolean, default: false },
		defaultProps: {
			type: Object,
			default() {
				return { label: 'name', children: 'children' };
			}
		}
	},
	data() {
		return {
			valueString: this.value,
			inputText: !this.multiple ? '' : [],
			inputValue: !this.multiple ? '' : [],
			selectConfig: {
				ref: 'mySelect',
				class: 'sw_tree_select',
				popperAppendToBody: false,
				multiple: !!this.multiple,
				clearable: !!this.clearable,
				filterable: !!this.filterable,
				placeholder: this.placeholder,
				collapseTags: this.collapseTags,
				filterMethod: this.handleRemoteMethod
			},
			treeConfig: {
				ref: 'myTree',
				checkStrictly: true,
				nodeKey: this.nodeKey,
				highlightCurrent: true,
				defaultExpandAll: true,
				checkOnClickNode: true,
				props: this.defaultProps,
				expandOnClickNode: false,
				showCheckbox: !!this.multiple,
				filterNodeMethod: this.handleFilterNode
			}
		};
	},
	computed: {
		treeFlatData() {
			return this.$treeToFlat(this.list);
		}
	},
	watch: {
		value(val) {
			this.valueString = val;
		},
		valueString: {
			handler(val) {
				this.$emit('input', val);
				this.dispatch('ElFormItem', 'el.form.change', [val]);
				if (!this.multiple) {
					this.inputValue = !val ? '' : val;
				} else {
					this.inputValue = !val ? [] : val.split(',');
				}
				this.initializeData();
			},
			immediate: true
		},

		inputValue(data) {
			if (!data) {
				this.valueString = '';
			} else if (Array.isArray(data)) {
				this.valueString = data.join();
			} else {
				this.valueString = data;
			}
		}
	},
	methods: {
		initializeData() {
			let arr = this.treeFlatData;
			if (!this.inputValue) {
				this.inputText = null;
				return false;
			}
			if (arr.length === 0) {
				setTimeout(() => {
					this.initializeData();
				}, 100);
				return false;
			}
			if (!this.multiple) {
				let checkedData = arr.find((n) => n.id === this.inputValue);
				this.$refs['myTree']?.setCurrentKey(this.inputValue);
				this.inputText = checkedData?.name;
			} else {
				let checkedDatas = arr.filter((n) => this.inputValue.some((k) => k === n.id));
				this.$refs['myTree']?.setCheckedKeys(this.inputValue);
				this.inputText = checkedDatas.map((n) => n.name);
			}
		},

		handleSelectClear() {
			this.inputText = null;
			this.inputValue = null;
			this.$refs['myTree'].filter('');
			if (!this.multiple) {
				this.$refs['myTree']?.setCurrentKey(null);
			} else {
				this.$refs['myTree'].setCheckedKeys([]);
			}
		},

		handleRemoveTag(val) {
			let index = this.inputText.indexOf(val);
			this.inputValue.splice(index, 1);
			this.inputText.splice(index, 1);
			this.$refs['myTree']?.setCheckedKeys(this.inputValue);
		},

		handleSelectChange() {},

		handleFilterNode(value, data) {
			let label = this.defaultProps.label;
			return data[label].indexOf(value) !== -1;
		},

		handleNodeClick(data, node) {
			if (!this.multiple) {
				this.inputValue = data.id;
				this.inputText = data.name;
				this.$refs['mySelect'].blur();
				this.$refs['myTree'].filter('');
			}
		},

		handleCheckChange(data, node) {
			if (!this.multiple) return false;
			this.inputValue = node.checkedKeys;
			this.inputText = node.checkedNodes.map((n) => n.name);
		},

		handleRemoteMethod(query) {
			this.$refs['myTree'].filter(query);
		}
	}
};
</script>
<style lang="scss" scoped>
.sw_tree_select::v-deep {
	.el-tree {
		width: 100%;
		padding: 5px 0;
		max-height: 288px;
		overflow: hidden;
		overflow-y: auto;
		border-radius: 4px;
	}
	.el-tag--info {
		display: inline-flex;
		align-items: center;
	}
	.el-select__tags-text {
		line-height: 1;
		flex-shrink: 0;
	}
	.el-tag__close {
		position: unset;
		margin: 0;
		margin-right: -4px;
		flex-shrink: 0;
	}
}
</style>
